amends "../snippetTest.pkl"

local set1 = Set(1, 2, 3)
local set2 = Set(1, 2, 3, 4, 5)

local comparator = (x, y) -> x < y
local deprecatedComparator = (x, y) -> if (x < y) -1 else if (x == y) 0 else 1

facts {
  ["isEmpty"] {
    Set().isEmpty
    !set1.isEmpty
  }

  ["every()"] {
    set1.every((x) -> x <= 3)
    !set1.every((x) -> x > 2)
  }

  ["any()"] {
    set1.any((x) -> x > 2)
    !set1.any((x) -> x > 3)
  }

  ["contains()"] {
    set1.contains(2)
    !set1.contains(4)
  }

  ["startsWith()"] {
    set1.startsWith(List())
    set1.startsWith(List(1, 2))
    !set1.startsWith(List(1, 3))
  }

  ["endsWith()"] {
    set1.endsWith(List())
    set1.endsWith(List(2, 3))
    !set1.endsWith(List(1, 3))
  }
}

examples {
  ["every"] {
    module.catch(() -> set1.every((x) -> "wrong type"))
  }

  ["any"] {
    module.catch(() -> set1.any((x) -> "wrong type"))
  }

  ["length"] {
    set1.length
  }

  ["filter()"] {
    set1.filter((x) -> x > 1)
    set1. filter((x) -> x > 3)
    module.catch(() -> set1. filter((x) -> "wrong type"))
  }

  ["map()"] {
    set1.map((x) -> x * 2)
    set1.map((x) -> List(x, x))
  }

  ["flatMap()"] {
    set1.flatMap((x) -> List(x, x + 1))
    module.catch(() -> set1.flatMap((x) -> "wrong type"))
  }

  ["flatten()"] {
    Set(List(1, 2), List(2, 3), List(4, 5)).flatten()
    Set(Set(1, 2), Set(2, 3), Set(4, 5)).flatten()
    Set(new Listing { 1; 2 }, new Listing { 2; 3 }, new Listing { 4; 5 }).flatten()
    Set(List(1, 2), Set(2, 3), new Listing { 4; 5 }).flatten()
    Set(List(), Set(), new Listing {}).flatten()
  }

  ["first"] {
    set1.first
  }

  ["rest"] {
    set1.rest
  }

  ["last"] {
    set1.last
  }

  ["single"] {
    Set(1).single
  }

  ["count()"] {
    set1.count((x) -> x >= 2)
    set1.count((x) -> true)
    set1.count((x) -> false)
    module.catch(() -> set1.count((x) -> "wrong type"))
  }

  ["find()"] {
    set1.find((x) -> x >= 2)
    set1.find((x) -> true)
    module.catch(() -> set1.find((x) -> "wrong type"))
  }

  ["findLast()"] {
    set1.findLast((x) -> x >= 2)
    set1.findLast((x) -> true)
    module.catch(() -> set1.findLast((x) -> "wrong type"))
  }

  ["take()"] {
    set1.take(0)
    set1.take(2)
    set1.take(4)
  }

  ["takeWhile()"] {
    set1.takeWhile((x) -> true)
    set1.takeWhile((x) -> false)
    set1.takeWhile((x) -> x < 3)
    module.catch(() -> set1.takeWhile((x) -> "wrong type"))
  }

  ["takeLast()"] {
    set1.takeLast(0)
    set1.takeLast(2)
    set1.takeLast(4)
  }

  ["takeLastWhile()"] {
    set1.takeLastWhile((x) -> true)
    set1.takeLastWhile((x) -> false)
    set1.takeLastWhile((x) -> x > 1)
    module.catch(() -> set1.takeLastWhile((x) -> "wrong type"))
  }

  ["drop()"] {
    set1.drop(0)
    set1.drop(2)
    set1.drop(4)
  }

  ["dropWhile()"] {
    set1.dropWhile((x) -> true)
    set1.dropWhile((x) -> false)
    set1.dropWhile((x) -> x < 3)
    module.catch(() -> set1.dropWhile((x) -> "wrong type"))
  }

  ["dropLast()"] {
    set1.dropLast(0)
    set1.dropLast(2)
    set1.dropLast(4)
  }

  ["dropLastWhile()"] {
    set1.dropLastWhile((x) -> true)
    set1.dropLastWhile((x) -> false)
    set1.dropLastWhile((x) -> x > 1)
    module.catch(() -> set1.dropLastWhile((x) -> "wrong type"))
  }

  ["fold()"] {
    set1.fold(0, (acc, x) -> acc + x)
    set1.fold(List(), (acc, x) -> acc.add(x))
    Set(1).fold(0, (acc, x) -> acc + x)
    Set().fold(0, (acc, x) -> acc + x)
  }

  ["foldBack()"] {
    set1.foldBack(0, (x, acc) -> x + acc)
    set1.foldBack(List(), (x, acc) -> acc.add(x))
    Set(1).foldBack(0, (x, acc) -> x + acc)
    Set().foldBack(0, (x, acc) -> x + acc)
  }

  ["reduce()"] {
    set1.reduce((x, y) -> x + y)
    Set(1).reduce((x, y) -> x + y)
    module.catch(() -> Set().reduce((x, y) -> x + y))
  }

  ["groupBy()"] {
    set2.groupBy((x) -> x)
    set2.groupBy((x) -> x.isOdd)
    set2.groupBy((x) -> true)
    Set().groupBy((x) -> x)
  }

  ["sortWith()"] {
    Set().sortWith(comparator)
    Set(3, 1, 1, 2, 1).sortWith(comparator)
    Set(3, 1, 2, 5, 4).sortWith(comparator)
  }

  ["sortWith() with deprecated 3-way comparator"] {
    Set().sortWith(deprecatedComparator)
    Set(3, 1, 1, 2, 1).sortWith(deprecatedComparator)
    Set(3, 1, 2, 5, 4).sortWith(deprecatedComparator)
  }

  ["toList()"] {
    set1.toList()
  }

  ["toSet()"] {
    set1.toSet()
  }

  ["intersect()"] {
    set1.intersect(Set())
    Set().intersect(set1)
    set1.intersect(Set(2, 3, 4))
    set1.intersect(Set(4, 5, 6))
  }

  ["difference()"] {
    set1.difference(Set())
    Set().difference(set1)
    set1.difference(Set(2, 3, 4))
    set1.difference(Set(4, 5, 6))
  }

  ["toMap()"] {
    set1.toMap((x) -> x, (x) -> 2 * x)
    local persons = Set(
      new Dynamic { name = "Pigeon"; age = 40 },
      new Dynamic { name = "Parrot"; age = 30 }
    )
    persons.toMap((p) -> p.name, (p) -> p)
  }

  ["add()"] {
    set1.add(42)
    Set().add(42)
  }

  ["minWith()"] {
    set1.minWith(comparator)
    List(1).minWith(comparator)
    module.catch(() -> List().minWith(comparator))
  }

  ["minWith() with deprecated 3-way comparator"] {
    set1.minWith(deprecatedComparator)
    List(1).minWith(deprecatedComparator)
    module.catch(() -> List().minWith(deprecatedComparator))
  }

  ["maxWith()"] {
    set1.maxWith(comparator)
    List(1).maxWith(comparator)
    module.catch(() -> List().maxWith(comparator))
  }

  ["maxWith() with deprecated 3-way comparator"] {
    set1.maxWith(deprecatedComparator)
    List(1).maxWith(deprecatedComparator)
    module.catch(() -> List().maxWith(deprecatedComparator))
  }

  ["zip()"] {
    Set(1, 2, 3).zip(Set(4, 5, 6))
    Set(1, 2, 3).zip(Set(4, 5, 6, 7, 8))
  }

  ["filterIndexed()"] {
    Set(1, 2, 3, 3, 2, 1).filterIndexed((i, n) -> i.isOdd)
    Set(1, 2, 3, 3, 2, 1).filterIndexed((i, n) -> i.isEven)
    Set(1, 2, 3, 3, 2, 1).filterIndexed((i, n) -> i.isOdd && n > 2)
    Set(1, 2, 3, 3, 2, 1).filterIndexed((i, n) -> i.isEven && n > 2)
  }

  ["mapIndexed()"] {
    Set(1, 2, 3, 3, 2, 1).mapIndexed((i, n) -> n * i)
    Set(1, 2, 3, 3, 2, 1).mapIndexed((i, n) -> i.isOdd && n.isEven)
  }

  ["mapNonNullIndexed()"] {
    Set(1, 2, 3, 4, 4, 3, 2, 1).mapNonNullIndexed((i, n) -> if (n.isOdd) null else n * i)
    Set(1, 2, 3, 4, null, 4, 3, 2, 1).mapNonNullIndexed((i, n) -> if (n?.isOdd ?? true) null else n * i)
  }

  ["flatMapIndexed()"] {
    Set(1, 2, 3, 3, 2, 1).flatMapIndexed((i, n) -> Set(n * i))
    Set(1, 2, 3, 3, 2, 1).flatMapIndexed((i, n) -> Set(i.isOdd && n.isEven))
  }

  ["foldIndexed()"] {
    set1.foldIndexed(0, (idx, x, y) -> idx + x + y)
    Set(1).foldIndexed(0, (idx, x, y) -> idx + x + y)
    Set().foldIndexed(0, (idx, x, y) -> idx + x + y)
  }

  ["toListing()"] {
    set1.toListing()
    Set().toListing()
  }

  ["toDynamic()"] {
    set1.toDynamic()
    Set().toDynamic()
  }

  ["filterNonNull()"] {
    set1.filterNonNull()
    Set().filterNonNull()
    Set(1, null, 2, null, 3).filterNonNull()
    Set(null, null, null).filterNonNull()
  }

  ["mapNonNull()"] {
    set1.mapNonNull((it) -> it)
    set1.mapNonNull((it) -> null)
    Set().mapNonNull((it) -> it)
    Set(1, null, 2, null, 3).mapNonNull((it) -> it)
  }

  ["filterIsInstance()"] {
    set1.filterIsInstance(Any)
    set1.filterIsInstance(Int)
    set1.filterIsInstance(Number)
    set1.filterIsInstance(Float)
    set1.filterIsInstance(String)
    Set(1, "2", 3.0, "4").filterIsInstance(String)
    Set().filterIsInstance(String)
  }

  ["split()"] {
    set1.split(0)
    set1.split(1)
    set1.split(2)
    set1.split(3)
    Set().split(0)
    module.catch(() -> set1.split(-1))
    module.catch(() -> set1.split(4))
  }

  ["partition()"] {
    set1.partition((it) -> it.isEven)
    set1.partition((it) -> it.isOdd)
    set1.partition((it) -> true)
    set1.partition((it) -> false)
    Set().partition((it) -> throw("unreachable"))
  }

  ["min"] {
    set1.min
    Set("Pigeon", "Barn Owl", "Parrot").min
    Set(3.9, -8.4, 42, -99999).min
    Set(42, 42.0).min
    Set(42.0, 42).min
    Set(11.gb, 100.mb, 12.tb).min
    Set(11.s, 100.ms, 3.d).min
    module.catch(() -> Set().min)
    module.catch(() -> Set(1, "Pigeon", 3.d).min)
  }

  ["max"] {
    set1.max
    Set("Pigeon", "Barn Owl", "Parrot").max
    Set(3.9, -8.4, 42, -99999).max
    Set(42, 42.0).max
    Set(42.0, 42).max
    Set(11.gb, 100.mb, 12.tb).max
    Set(11.s, 100.ms, 3.d).max
    module.catch(() -> Set().max)
    module.catch(() -> Set(1, "Pigeon", 3.d).max)
  }

  ["minBy()"] {
    set1.minBy((it) -> it)
    set1.minBy((it) -> -it)
    Set("Pigeon", "Barn Owl", "Parrot").minBy((it) -> it.length)
    Set("Pigeon", "Barn Owl", "Parrot").minBy((it) -> it.reverse())
    Set(11.gb, 100.mb, 12.tb).minBy((it) -> it.value)
    Set(11.gb, 100.mb, 12.tb).minBy((it) -> it)
    Set(11.s, 100.ms, 12.min).minBy((it) -> it.value)
    Set(11.s, 100.ms, 12.min).minBy((it) -> it)
    module.catch(() -> Set().minBy((it) -> it))
    module.catch(() -> Set(1, "Pigeon", 3.d).minBy((it) -> it))
  }

  ["maxBy()"] {
    set1.maxBy((it) -> it)
    set1.maxBy((it) -> -it)
    Set("Pigeon", "Barn Owl", "Parrot").maxBy((it) -> it.length)
    Set("Pigeon", "Barn Owl", "Parrot").maxBy((it) -> it.reverse())
    Set(11.gb, 100.mb, 12.tb).maxBy((it) -> it.value)
    Set(11.gb, 100.mb, 12.tb).maxBy((it) -> it)
    Set(11.s, 100.ms, 12.min).maxBy((it) -> it.value)
    Set(11.s, 100.ms, 12.min).maxBy((it) -> it)
    module.catch(() -> Set().maxBy((it) -> it))
    module.catch(() -> Set(1, "Pigeon", 3.d).maxBy((it) -> it))
  }

  ["sort()"] {
    set1.sort()
    Set(3.9, -8.4, 42, -99999).sort()
    Set("Pigeon", "Barn Owl", "Parrot").sort()
    Set(11.gb, 100.mb, 12.tb).sort()
    Set(11.s, 100.ms, 3.d).sort()
    Set().sort()
    module.catch(() -> Set(1, "Pigeon", 3.d).sort())
  }

  ["sortBy()"] {
    set1.sortBy((it) -> it)
    set1.sortBy((it) -> -it)
    Set("Pigeon", "Barn Owl", "Parrot").sortBy((it) -> it.length)
    Set("Pigeon", "Barn Owl", "Parrot").sortBy((it) -> it.reverse())
    Set(11.gb, 100.mb, 12.tb).sortBy((it) -> it.value)
    Set(11.gb, 100.mb, 12.tb).sortBy((it) -> it)
    Set().sortBy((it) -> throw("unreachable"))
    Set(0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10).sortBy((it) -> 42)
  }

  ["repeat()"] {
    set1.repeat(0)
    set1.repeat(1)
    set1.repeat(5)
    Set().repeat(0)
    Set().repeat(1)
    Set().repeat(5)
    module.catch(() -> set1.repeat(-1))
  }

  ["reverse()"] {
    set1.reverse()
    set1.reverse().reverse()
    Set(1, "Pigeon", 3.d).reverse()
    Set().reverse()
  }
}
